package wbhproject.servlets;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

import org.apache.log4j.Logger;

import com.google.gson.Gson;

import wbhproject.model.ControllerUnit;
import wbhproject.model.Measure;
import wbhproject.model.MeasurePoint;
import wbhproject.tools.Configuration;

/**
 * Servlet implementation class ServiceServlet 
 * Author: Thomas Aulich Date:
 * 2015-01-19
 */
public class ServiceServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	static Logger log = Logger.getLogger(ServiceServlet.class);
	private Configuration myConfig;
	private Context envContext;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public ServiceServlet() {
		super();
		log.debug("Servlet construction ...");
		// TODO Auto-generated constructor stub
		myConfig = Configuration.getInstance();
		log.debug("... Configuration loaded ...");
		try {
			envContext = new InitialContext();
		} catch (NamingException e) {
			log.error("InitialContext could not be loaded ...");
			e.printStackTrace();
		}
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		log.debug("doPost was called ...");
		sendResponse(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		log.debug("doPost was called ...");
		sendResponse(request, response);
	}

	private void sendResponse(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		log.debug("sendResponse was called ...");
		String mode = request.getParameter("mode");
		if (mode == null) {
			response.sendError(400, "Missing mode-parameter!");
		} else {
			mode = mode.toLowerCase();
			log.debug("mode-parameter of request is: " + mode);
			switch (mode) {
			case "getmeasurepoint":
				sendResponseGetMeasurePoint(request, response);
				break;
			case "getmeasure":
				sendResponseGetMeasure(request, response);
				break;
			default:
				response.sendError(400, "Invalid mode-parameter!");
			}
		}
	}

	private void sendResponseGetMeasurePoint(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String jsonString = new String();
		try {
			log.debug("Try to establish database connection ...");
			DataSource ds = (DataSource) envContext.lookup(myConfig
					.getDataSourceContext());
			Connection con = ds.getConnection();
			Statement stmt1 = con.createStatement();
			String SQLString = new String();
			SQLString = "SELECT * FROM controllerunit";
			ResultSet rs1 = stmt1.executeQuery(SQLString);
			log.debug("Running query to select all measureoints ...");
			List<MeasurePoint> list = new ArrayList<MeasurePoint>();
			while (rs1.next()) {
				ControllerUnit controllerUnit = new ControllerUnit(
						rs1.getLong("id"), rs1.getString("serveraddress"),
						rs1.getString("stationname"),
						rs1.getString("stationalias"), rs1.getBoolean("active"));
				log.debug("Performing registering for controllerunit: "
						+ controllerUnit.getDescription());
				Statement stmt2 = con.createStatement();
				ResultSet rs2 = stmt2
						.executeQuery("SELECT * FROM measurepoint WHERE controllerunit = "
								+ rs1.getLong("id") + "");
				while (rs2.next()) {
					log.debug("Registering measurepopint "
							+ rs2.getString("symbolname"));
					MeasurePoint measurePoint = new MeasurePoint(
							rs2.getLong("id"), controllerUnit,
							rs2.getString("symbolname"),
							rs2.getString("registeraddress"),
							rs2.getString("cmt"), rs2.getString("format"),
							rs2.getInt("decimaldigits"));
					log.debug("Registering measurepoint: "
							+ measurePoint.getDescription());
					list.add(measurePoint);
				}
			}
			Gson gson = new Gson();
			jsonString += gson.toJson(list);
		} catch (Exception e) {
			log.error("Error while reading data: " + e.getMessage());
			e.printStackTrace();
		}
		// Send back the result
		response.setContentType("application/json");
		PrintWriter out = response.getWriter();
		out.print(jsonString);
	}

	/**
	 * The getmeasure-thing should create a JSON
	 * depending from the request-parameters
	 * it should be possible to influence by parameter
	 * what this feature delivers...
	 * In the first DEMO-Version it delivers all measures for 
	 * a specific MeasurePoint.
	 * For that reason MeasurePoint is a needed parameter ...
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	private void sendResponseGetMeasure(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String jsonString = new String();
		log.debug("sendResponseGetMeasure was called ...");
		String measurepoint = request.getParameter("measurepoint");
		if (measurepoint == null) {
			response.sendError(400, "Missing measurepoint-parameter!");
		} else {
			measurepoint = measurepoint.toLowerCase();
			try {
				log.debug("Try to establish database connection ...");
				DataSource ds = (DataSource) envContext.lookup(myConfig
						.getDataSourceContext());
				Connection con = ds.getConnection();
				Statement stmt1 = con.createStatement();
				String SQLString = new String();
				SQLString = "SELECT * FROM measure where measurepoint = "  + measurepoint;
				ResultSet rs1 = stmt1.executeQuery(SQLString);
				log.debug("Running query to select all measures for specific measurepoint ...");
				List<Measure> list = new ArrayList<Measure>();
				while (rs1.next()) {
					Measure measure = new Measure(rs1.getLong("id"), null, rs1.getDouble("val"), rs1.getTimestamp("at"));
					list.add(measure);
				}
				Gson gson = new Gson();
				jsonString = gson.toJson(list);
			} catch (Exception e) {
				log.error("Error while reading data: " + e.getMessage());
				e.printStackTrace();
			}
		}
		// Send back the result
		response.setContentType("application/json");
		PrintWriter out = response.getWriter();
		out.print(jsonString);
	}
}
